home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-06 | 17.6 KB | 406 lines | [TEXT/CWIE] |
- /* GDOpenWindow.c
- Copyright © 1989-1995 Denis G. Pelli
-
- EXAMPLE:
-
- Open your window by saying:
- window=GDOpenWindow(device);
- When you're through with the window, get rid of it by calling:
- GDDisposeWindow(window);
- Besides closing the window and disposing of the allocated memory structures
- GDDisposeWindow also restores the device's color table and clut.
-
- SUMMARY:
-
- window=GDOpenWindow(device) opens a full-screen window on the specified screen,
- call GDGrayColorTable(device) which gives the device a standard gray color table
- (if it doesn't already), and calls AddExplicitPalette(window), which allows you
- to specify colors to paint with by using PmForeColor() and PmBackColor(). The
- window truly fills the screen: any rounded corners are made square and if the
- window is on the main screen then the Menu Bar is hidden. The screen occupies
- the content area of the window; the window's frame (one-pixel black line border
- and title bar) is off that screen, but will appear on other screens that form
- contiguous parts of your desktop. The elegant solution to this, which perhaps
- someone will implement, would be to define a new window type that has no frame.
-
- GDDisposeWindow(window) closes and discards a color window, disposing of any
- palette or color table, generally undoing whatever GDOpenWindow1 did.
-
- AddExplicitPalette(window) adds a palette to a color window or GWorld with all
- the colors marked as pmExplicit. This allows you to use PmForeColor() and
- PmBackColor() to specify the value you want poked into each pixel by QuickDraw
- operations, e.g. EraseRect() and DrawString().
-
- RemovePalette(window) disposes of the palette created by AddExplicitPalette.
-
- SwapWindowExplicitMode(window,&explicit) swaps the contents of the Boolean
- argument with the "explicit" bit (bit 14 of the ctFlags field) in the color
- table. The use of this bit is documented in "VideoToolbox:Notes:CopyBits
- slavishly". After much experimentation I decided that it's not useful, but I
- leave this routine here for others that wish to experiment. Note that when
- GDOpenWindow() creates a window, the window shares the color table belonging to
- the device, so calling SwapWindowExplicitMode() modifies the shared table, i.e.
- the device's color table is modified. You should restore it by calling
- MakeColorTableExplicit() again. Failing to restore it will have cosmetic
- aftereffects, even after your application quits. The most obvious aftereffect is
- that documents in Word will be largely gray.
-
- GetBitMapPtr(window) returns a pointer to the window's bitmap or pixmap.
-
- IsGWorldPtr(window) returns true only if the window is a GWorldPtr.
-
- COMMENTS:
-
- Please read "VideoToolbox:Notes:CopyBits slavishly". QuickDraw likes to
- pick a bunch of good colors and stuff them in the clut, in essentially random
- order, except that white is first and black is last. It wants you to specify any
- desired color as an RGB triplet and then it picks the mysterious clut index that
- would provide the closest match. If you're processing grayscale images, then
- QuickDraw's approach involves a lot of overhead involving inverse color tables,
- and makes the numbers stored in your pixels meaningless (unless you look them up
- in the associated color table or palette).
-
- The philosophy of the VideoToolbox is to bypass QuickDraw's color model, and
- work explicitly with the numbers that are stored in your pixels.
- SetPixelsQuickly will efficiently poke (or peek) the numbers in your PixMap.
- However, if you want to use QuickDraw's handy drawing operations, especially
- EraseRect() and DrawString() then you need a way to specify the foreground and
- background colors. AddExplicitPalette() gives your window a palette in which all
- the colors are marked as pmExplicit. This tells the palette manager to use your
- arguments to PmForeColor() and PmBackColor() literally.
-
- I suggest that you control the clut by calling GDUncorrectedGamma() and
- GDSetEntries(), since these calls directly control the video device driver,
- bypassing the Color Manager. Since the Color and Palette Managers don't know
- that you've changed the color environment they can't react to it, and will
- passively let you continue to specify colors by their clut index. For example,
- the Palette Manager religiously believes that the first clut entry should be
- white and the last one black, and it will change them back to those values if
- you change them and it finds out about it. If you use the Color Manager
- SetEntries call then the Paletter Manger WILL find out because a record is made
- in the ColorTable. Calling GDSetEntries() bypasses the Color Manager. Instead,
- the video device driver writes directly to the clut and the ColorTable is not
- modified. Of course, this means that you should ignore the ColorTable since it
- will no longer reflect the contents of the clut.
-
- Every time you access the stdio package, e.g. printf or getch(), THINK C will
- move the console window to the front, which may obscure your window. You can
- bring your window back to the front by calling BringToFront() or SelectWindwo().
-
- NOTE:
- Tom Busey (busey@indiana.edu) writes: "I'm using an 8-bit SuperMac ColorCard
- that a used computer dealer gave me when I ordered a Toby card. I discovered
- that the status and control calls for GDUncorrectedGamma return -17 and -18
- respectively, which means that the driver doesn't support different gammas.
- GDUncorrectedGamma returns an error message, but GDOpenWindow doesn't use the
- error message or pass it back to the calling program. I'm wondering if there are
- people using GDOpenWindow who think that they are getting a linear gamma but who
- are actually getting an error message and not learning about it."
- Tom's facts are right, but he needn't worry. A few video drivers, e.g.
- Radius PowerView, and apparently the SuperMac ColorCard, don't implement gamma
- tables at all, but the error from GDUncorrectedGamma is probably not a concern.
- The real test is to run TimeVideo. TimeVideo does a write-and-read-back test of
- the clut of your video card. If that test passes then you can safely conclude
- that there's no gamma translation going on. So, as nearly every document in the
- VideoToolbox says: run TimeVideo and read the report.
- Here's how gamma tables work. According to the Apple manual (Designing
- Cards and Drivers), the values in the rgb triplets that you supply in a
- setentries call to the video driver are first translated via the gamma table
- (each r,g, and b component separately) before being loaded into the CLUT
- hardware table. Most drivers maintain a gamma table internally (in computer
- memory) and allow you to get and set it via the GDGetGamma and GDSetGamma calls.
- A few video drivers (Radius PowerView, SuperMac ColorCard) don't support gamma
- tables. They load your rgb values directly into the CLUT, without translation.
- However, for users of the VideoToolbox that's usually fine, since that's exactly
- the behavior that we routinely request by calling GDUncorrectedGamma. Of course,
- if you want to load a custom gamma table, other than the identity
- transformation, then you'll be calling GDSetGamma, and you should make sure it
- does not return an error. (Alas, the Radius PowerView driver more or less
- ignores the set- and get-gamma requests--GDGetGamma returns a table that's all
- zeroes--but the driver fails to report an error. I wrote to the Radius
- programmer a year ago, but they're no longer interested in working on that
- product.)
-
-
- PROBLEM:
- How can I tell whether I've got a CGrafPtr or a GWorldPtr? (In one case I'll call
- GetGWorldDevice, in the other case I'll get max device.)
- I noticed that the portVersions are 0xc001 and 0xc000. Should I use that to tell?
-
- ANSWER FROM APPLE DEVSUPPORT (8/93):
- You can use GetGWorldDevice() on GWorldPtr, GrafPort or CGrafPort. Use
- TestDeviceAttibute() to test if the returned GDHandle is a "real" screen or not.
-
- Also, you should refer to the tech note “RowBytes Revealed II” (available on the
- June Developer CD) which states:
-
- You'll notice in Figure 1 that the portVersion field of a cGrafPort coincides
- with the location of the rowBytes field of a grafPort. Remember, a cGrafPort has
- the same size as a grafPort. During debugging, you can use the same information
- that CopyBits uses to identify cGrafPorts.
-
- If you use a grafPort template to display memory for an unknown grafPort, you
- can tell if it is a cGrafPort because the rowBytes will be equal to 0xC000. The
- 0xC corresponds to the two high bits being set in the portVersion field of a
- cGrafPort. Since these bits can not be set in a grafPort, you know you have a
- cGrafPort. In addition, if the bottom bit of the portVersion field is set, then
- it is a gWorld. Thus, if your rowBytes field has a value of 0xC001, then you
- know you have a gWorld.
-
- CONCLUSION:
- This advice is implemented in the routine IsGWorldPtr(window).
-
- HISTORY:
-
- 12/88 dgp wrote it
- 8/5/89 added call to GDUncorrectedGamma, so I couldn't forget.
- 8/15/89 dgp trivia
- 3/20/90 dgp make compatible with MPW C.
- 3/29/90 dgp changed declared returned type from WindowPtr to CWindowPtr, which
- is what it's really been all along. Same change to argument of
- GDDisposeWindow(). The new offscreen GWorld calls for the first time
- make it easier to honestly declare one's windows as color rather
- than pretending they're not.
- 8/24/91 dgp Made compatible with THINK C 5.0.
- 2/1/92 dgp Made optional the device argument to GDDisposeWindow(). If it's
- NULL, then it will be determined automatically from window.
- 2/3/93 dhb Extracted AddExplicitPalette from GDOpenWindow.
- 2/21/93 dgp HideMenuBar if window is on main screen.
- 2/23/93 dgp AddExplicitPalette() returns immediately unless it receives a color
- window.
- Added GDOpenWindow1() and GDDisposeWindow1(), which both use
- a WindowPtr, instead of a less convenient CWindowPtr.
- 3/5/93 dgp Added calls to UnclipScreen() and RestoreScreenClipping(), so the window
- now truly fills the whole screen. Edited GDOpenWindow() for clarity.
- 3/7/83 dgp Added calls to GDSaveGamma(device) and GDRestoreGamma(device).
- 4/16/93 dgp Cosmetic editing.
- 5/22/93 dgp Added RemovePalette(), but didn't test it.
- 1/27/94 dgp Cosmetic editing.
- 3/5/94 dgp Decided that RemovePalette() works fine now.
- 6/8/94 dgp AddExplicitPalette now calls the new MakeColorTableExplicit(), which
- sets the Color Table ctFlags to indicate that
- the Color Table refers explicitly
- to the explicit palette. This tells CopyBits to treat
- the pixels as numbers, not indices.
- 6/13/94 dgp In response to query by David Brainard I now document above
- the obscure fact that GDOpenWindow's frame will appear on
- other screens that are contiguous parts of the desktop.
- 8/11/94 dhb & dgp David Brainard discovered that MakeColorTableExplicit(), which
- is called by AddExplicitPalette, which is called by GDOpenWindow1, was affecting
- not just the new window's color table, but was also affecting the device's color
- table (because they share the same color table), and that the device's color
- table was not restored. "The symptom is that if you subsequently launch
- Microsoft Word, the background of the text window takes on a strange color
- (grey) in regions where there is text," and the problem persists until reboot.
- The solution is to give our window its own color table, which we can
- safely modify.
- 8/12/94 dhb & dgp on 8/11 denis inadvertently introduced a bug into GDDisposeWindow1,
- moving the call to GetWindowDevice() to a point after the window
- was disposed of. David fixed it, moving the call back where it belonged.
- 8/14/94 dgp GDOpenWindow1 now gets the color table from the window's device instead
- of the main device.
- 8/17/94 dgp make color table NOT explicit when GDDisposeWindow1 is called.
- 9/5/94 dgp removed assumption in printf's that int==short.
- 10/10/94 dgp GDOpenWindow1 now associates correct device's color table with window,
- not MainDevice's.
- 10/24/94 dgp GDOpenWindow1 returns NULL if there's no driver associated with the device.
- 10/25/94 dgp Added GDGrayColorTable(device), which gives the device a standard gray color table.
- 11/2/94 dgp Leave the explicit bit alone. For the adventurous I provide the
- MakeColorTableExplicit() routine and documentation in
- VideoToolbox:Notes:"CopyBits slavishly".
- 11/17/94 dgp renamed IsWindow to IsGrafPtr. Renamed IsOffScreen to IsGWorldPtr.
- 4/11/95 dgp Fixed assertion failure in GDGrayWindow; the rsrc id of the 2-bit gray ramp is 2,
- not 32+2.
- 4/11/95 dgp transferred some documentation of IsGWorldPtr from GetScreenDevice.c to above.
- */
- #include "VideoToolbox.h"
-
- #define MAKE_COLOR_TABLE 0
-
- WindowPtr GDOpenWindow1(GDHandle device)
- {
- return (WindowPtr)GDOpenWindow(device);
- }
-
- void GDDisposeWindow1(WindowPtr window)
- {
- GDDisposeWindow((CWindowPtr) window);
- }
-
- CWindowPtr GDOpenWindow(GDHandle device)
- {
- CWindowPtr window;
- Rect r;
- GDHandle oldDevice;
-
- if(device==NULL || (*device)->gdRefNum==0)return NULL;
- r=(*device)->gdRect; // rect of desired screen in global coordinates
- GDSaveGamma(device);
- GDUncorrectedGamma(device);
- UnclipScreen(device);
- GDGrayColorTable(device);
- oldDevice=GetGDevice();
- SetGDevice(GetMainDevice()); // Needed for window to work properly.
- window=(CWindowPtr)NewCWindow(NULL,&r,"\p",TRUE,plainDBox,(WindowPtr) -1L,0,123L);
- (*window->portPixMap)->pmTable=(**(**device).gdPMap).pmTable;
- SetGDevice(oldDevice);
- AddExplicitPalette((WindowPtr)window);
- return window;
- }
-
- void GDGrayColorTable(GDHandle device)
- // give the device a standard gray color table
- {
- ColorTable **table;
- PixMap **pm;
- int id;
-
- if(device==NULL)return;
- pm=(**device).gdPMap;
- table=(**pm).pmTable;
- id=(**pm).pixelSize;
- if(id>2)id+=32;
- if((**device).gdType==clutType && (**table).ctSeed!=id){
- // Give the device a standard gray-ramp color table
- table=GetCTable((**pm).pixelSize+32); // gray ramp
- assert(table!=NULL);
- assert((**(**pm).pmTable).ctSize==(**table).ctSize);
- memcpy(*(**pm).pmTable,*table,8+((**table).ctSize+1)*sizeof(ColorSpec));
- DisposeHandle((Handle)table);
- table=(**pm).pmTable;
- (**table).ctFlags|=0x8000; // mark as belonging to a device
- GDeviceChanged(device);
- }
- }
-
- void GDDisposeWindow(CWindowPtr window)
- // Dispose of window and palette and restore the screen's clut and clipping.
- {
- GDHandle device;
-
- if(window==NULL)return;
- RemovePalette((WindowPtr)window);
- #if MAKE_COLOR_TABLE
- DisposHandle((Handle)(*((CGrafPtr)window)->portPixMap)->pmTable);
- #endif
- device=GetWindowDevice((WindowPtr)window);
- DisposeWindow((WindowPtr)window);
- if(device==NULL)return;
- GDRestoreGamma(device);
- GDRestoreDeviceClut(device);
- RestoreScreenClipping(device);
- }
-
- void AddExplicitPalette(WindowPtr window)
- // Create a palette for the color window and mark all the entries as explicit.
- // Copy the entries from the window's device.
- {
- GDHandle device;
- CTabHandle ct;
- PaletteHandle palette;
- int colors;
- #if MAKE_COLOR_TABLE
- int i,error;
- #endif
-
- if(window==NULL)return;
- if(((CGrafPtr)window)->portVersion>=0) return; // Not a color window, return.
- device=GetWindowDevice(window);
- if(device==NULL)PrintfExit(
- "AddExplicitPalette: window has no device! %s line %d.\n",__FILE__,__LINE__);
- ct=(**(**device).gdPMap).pmTable;
- colors=(*ct)->ctSize+1;
- #if MAKE_COLOR_TABLE
- error=HandToHand((Handle *)&ct);
- if(error)PrintfExit("%s line %d: error %d in copying color table\n"
- ,__FILE__,__LINE__,error);
- (*ct)->ctFlags &= 0x7fff; // clear "device" bit
- for(i=0;i<colors;i++) (*ct)->ctTable[i].value=i;
- (*ct)->ctSeed=GetCTSeed();
- (*((CGrafPtr)window)->portPixMap)->pmTable=ct;
- #endif
- palette=NewPalette(colors,ct,pmExplicit+pmTolerant,0);
- SetPalette(window,palette,0);
- }
-
- /*
- RemovePalette may look dangerous. I worried that the Window or
- Palette Manager might become confused if it later tries to access the
- window's palette, which no longer exists. However, by trial and error
- I've found that this works fine, and that my attempts to make explicit the
- fact that the palette is gone, e.g. by calling SetPalette(window,NULL,0),
- all produced crashes. I conclude that the Palette or Window Manager monitors
- the calls to DisposePalette and thus knows that the palette is gone.
- */
- void RemovePalette(WindowPtr window)
- {
- if(window==NULL)return;
- DisposePalette(GetPalette(window));
- }
-
- void SwapWindowExplicitMode(CWindowPtr window,Boolean *explicit)
- // Get and set bit 14 of the ctFlags field of the window's color table.
- // This is only relevant to a CopyBits from an offscreen
- // graphics environment, be it PixMap or GWorld, to an onscreen window.
- // See Inside Mac VI, page 20-17. To get the full story see "CopyBits slavishly" in
- // VideoToolbox:Notes.
- {
- int i,ok;
- ColorTable **ct;
- Boolean oldExplicit;
-
- if(window==NULL)return;
- // If it's a GWorldPtr then we must lock the pixels to access the pixmap.
- if((window->portVersion&0xc001)==0xc001){
- ok=LockPixels(GetGWorldPixMap(window));
- if(!ok)return;
- }
- ct=(*window->portPixMap)->pmTable;
- oldExplicit=((*ct)->ctFlags&0x4000)!=0;
- if(*explicit){
- (*ct)->ctFlags|=0x4000;
- for(i=(*ct)->ctSize;i>=0;i--)(*ct)->ctTable[i].value=i;
- }else{
- (*ct)->ctFlags&=~0x4000;
- }
- *explicit=oldExplicit;
- }
-
- // CAUTION: The PixMap handles are not locked. So don't move memory. The
- // returned pointers will become invalid as soon as you call any routine
- // that moves memory. CopyBits and CopyBitsQuickly are ok.
- BitMap *GetBitMapPtr(CWindowPtr window)
- {
- BitMap *bits;
- int ok;
- PixMapPtr *pm;
-
- if(IsGWorldPtr(window)){
- // It's a GWorldPtr, lock the pixels, return pixmap ptr.
- ok=LockPixels(GetGWorldPixMap((GWorldPtr)window));
- if(!ok)return NULL;
- pm=GetGWorldPixMap((GWorldPtr)window);
- // HLock((Handle)pm);
- bits = (BitMap *)*pm;
- }else if(!IsGrafPtr(window)){
- pm=window->portPixMap;
- // HLock((Handle)pm);
- bits = (BitMap *)*pm;
- }else{
- bits = &((WindowPtr)window)->portBits;
- }
- return bits;
- }
-
- Boolean IsGWorldPtr(CWindowPtr window) // Is it a GWorldPtr?
- {
- return (window->portVersion&0xc001) == 0xc001;
- }
-
-
- Boolean IsGrafPtr(CWindowPtr window) // Is it a WindowPtr?
- {
- return window->portVersion>=0;
- }
-
-